﻿using System;
using System.Collections.Generic;

using VSTalk.Engine.Core.Context;
using VSTalk.Model;
using VSTalk.Tools;

namespace VSTalk.Engine.Core.EntitySession
{
    public class SessionModel : ISessionModel, IDisposable
    {
        private readonly IDictionary<Client, IClientContext> _clients = new Dictionary<Client, IClientContext>();
        private readonly IDictionary<Interlocutor, InterlocutorContext> _interlocutors = new Dictionary<Interlocutor, InterlocutorContext>();
        private readonly IDictionary<Room, RoomContext> _rooms = new Dictionary<Room, RoomContext>();
        
        private ISubscription _clientUnit;
        private ISubscription _interlocutorUnit;
        private ISubscription _roomUnit;

        public void Initialize(IModelContext model)
        {
            _clientUnit = model.Clients.HandleRemoveChanges(removed: client =>
            {
                if (_clients.ContainsKey(client))
                {
                    _clients[client].StopListen();
                    _clients.Remove(client);
                }
            });
            _interlocutorUnit = model.Interlocutors.HandleRemoveChanges(removed: interlocutor =>
            {
                if (_interlocutors.ContainsKey(interlocutor))
                {
                    _interlocutors[interlocutor].StopListen();
                    _interlocutors.Remove(interlocutor);
                }
            });
            _roomUnit = model.Rooms.HandleRemoveChanges(removed: room =>
            {
                if (_rooms.ContainsKey(room))
                {
                    _rooms[room].StopListen();
                    _rooms.Remove(room);
                }
            });
        }

        public IClientContext GetClientContext(Client client)
        {
            if (_clients.ContainsKey(client))
            {
                return _clients[client];
            }
            var context = new ClientContext(client);
            _clients.Add(client, context);
            context.StartListen();
            return context;
        }

        public IInterlocutorContext GetInterlocutorContext(Interlocutor interlocutor)
        {
            if (_interlocutors.ContainsKey(interlocutor))
            {
                return _interlocutors[interlocutor];
            }
            var context = new InterlocutorContext(interlocutor);
            _interlocutors.Add(interlocutor, context);
            context.StartListen();
            return context;
        }

        public IRoomContext GetRoomContext(Room room)
        {
            if (_rooms.ContainsKey(room))
            {
                return _rooms[room];
            }
            var context = new RoomContext(room);
            _rooms.Add(room, context);
            context.StartListen();
            return context;
        }

        public void Dispose()
        {
            _clientUnit.Unsubscribe();
            _interlocutorUnit.Unsubscribe();
            _roomUnit.Unsubscribe();
        }
    }
}